#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <sysexits.h>
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>

#include <xmlsec/app.h>
#include <xmlsec/dl.h>
#include <xmlsec/strings.h>
#include <ecgi.h>
#include <xmlsec/xmltree.h>
#include <libxml/xmlsave.h>

#include "../mcx/mcx.h"
#include "prepaid.h"

void usage(int show) {
  fputs("Usage:\n", stderr);
  if(show & 1)
    fputs("\tprepaid add file\n\t\t'file': an XML block containing a <ds:KeyInfo>\n", stderr);
  if(show & 2)
    fputs("\tprepaid pay id currency amount\n\t\t'id': index returned from previous 'add' command (0-1023)\n\t\t'currency': currency of payment\n\t\t'amount': amount of payment\n", stderr);
  if(show & 4)
    fputs("\tprepaid list type\n\t\t'type': 'keys' or 'auth' displays ids of keys waiting for authorities or generated authorities respectively\n", stderr);
  if(show & 8)
    fputs("\tprepaid get type index\n\t\t'type': 'keys' or 'auth' to retrieve keys or authorities\n\t\t'index': index returned from previous 'add' command\n", stderr);
  exit(EX_USAGE);
}

int main(int argc, char **argv) {
  xmlInitParser();
  assert(!xmlSecInit());
#ifndef XMLSEC_NO_CRYPTO_DYNAMIC_LOADING
  assert(!xmlSecCryptoDLLoadLibrary("openssl"));
#endif
  assert(!xmlSecCryptoAppInit(NULL));
  assert(!xmlSecCryptoInit());
  srand(getpid());
  if(argc < 2)
    usage(-1);
  // add key -> id
  if(!strcmp(argv[1], "add")) {
    xmlDocPtr doc;
    xmlNodePtr key;
    unsigned ret;
    
    if(argc != 3)
      usage(1);
    doc = validateXmlFile(URI_SCHEMA_CHARON, argv[2]);
    key = xmlSecFindNode(xmlDocGetRootElement(doc), "KeyInfo", xmlSecDSigNs);
    assert(key);
    ret = pp_addkey(key);
    printf("ID: %d\n", ret);
    return 0;
  } else if(!strcmp(argv[1], "pay")) {
    xmlDocPtr auth;
    unsigned long index;
    char *ptr;

    if(argc != 5)
      usage(2);
    index = strtoul(argv[2], &ptr, 10);
    if((index >= 1024) || *ptr)
      usage(2);
    auth = pp_pay(index, argv[3], argv[4]);
  } else if(!strcmp(argv[1], "list")) {
    if(argc != 3)
      usage(4);
    if(!strcmp(argv[2], "keys")) {
      DIR *d;
      char *buf;
      struct dirent *de;

      buf = alloca(strlen(pp_authdir()) + 20);
      d = opendir(pp_keydir());
      assert(d);
      while((de = readdir(d))) {
	int index;
	struct stat st;
	
	if(sscanf(de->d_name, "%d.xml", &index)) {
	  sprintf(buf, "%s/%s", pp_authdir(), de->d_name);
	  if(stat(buf, &st))
	     printf("%d\n", index);
	}
      }
      closedir(d);
    } else if(!strcmp(argv[2], "auth")) {
      DIR *d;
      struct dirent *de;

      d = opendir(pp_authdir());
      assert(d);
      while((de = readdir(d))) {
	int index;
	
	if(sscanf(de->d_name, "%d.xml", &index)) {
	  printf("%d\n", index);
	}
      }
      closedir(d);
    } else
      usage(4);
  } else if(!strcmp(argv[1], "get")) {
    char *tmp;
    int index;
    xmlDocPtr doc;
    xmlSaveCtxtPtr ctxt;
    
    if(argc != 4)
      usage(8);
    index = strtoul(argv[3], &tmp, 10);
    if((index >= 1024) || *tmp)
      usage(8);
    if(!strcmp(argv[2], "keys"))
      doc = pp_getkey(index);
    else if(!strcmp(argv[2], "auth"))
      doc = pp_getauth(index);
    else
      usage(8);
    ctxt = xmlSaveToFd(1, "UTF-8", XML_SAVE_NO_EMPTY|XML_SAVE_NO_DECL);
    xmlSaveDoc(ctxt, doc);
    xmlSaveClose(ctxt);
  } else {
    usage(-1);
  }
  return 0;
}
